home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / lang / FPL_v147.lha / fpl / src / sscanf.c < prev    next >
C/C++ Source or Header  |  1995-07-07  |  9KB  |  385 lines

  1.  
  2. #include <limits.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5.  
  6. #include "script.h"
  7.  
  8. #define    inchar()    ((c = string[pos++]),                \
  9.              pos>stringlen ?                \
  10.              EOF : (++read_in, c))
  11. #define    conv_error()    return(done)
  12. #define input_error()    return(-1)
  13. #define    memory_error()    return(-1)
  14.  
  15. #define SCALL(x)        if(x) return -1;
  16.  
  17. /* Read formatted input from String according to the format string
  18.    FORMAT, using the argument list in ARG.
  19.    Return the number of assignments made, or -1 for an input error.  */
  20. long
  21. Sscanf(struct Data *scr,
  22.        uchar *string,
  23.        uchar *format,
  24.        long argc,
  25.        void **param_array,
  26.        uchar *param_types)
  27. {
  28.   struct Identifier *ident;
  29.   long stringlen = string?FPL_STRLEN(string):0; /* length of string to parse */
  30.   long pos=0; /* current scan point! */
  31.   char *f = format;
  32.   char fc;        /* Current character of the format.  */
  33.   long done = 0;    /* Assignments done.  */
  34.   long read_in = 0;    /* Chars read in.  */
  35.   long c;        /* Last char read.  */
  36.   long do_assign;    /* Whether to do an assignment.  */
  37.   long width;        /* Maximum field width.  */
  38.  
  39.   /* Type modifiers.  */
  40.   char is_short, is_long, is_long_double;
  41. #ifdef    HAVE_LONGLONG
  42.       /* We use the `L' modifier for `long long int'.  */
  43. #define    is_longlong    is_long_double
  44. #else
  45. #define    is_longlong    0
  46. #endif
  47.   /* If a [...] is a [^...].  */
  48.   char not_in;
  49.   /* Base for integral numbers.  */
  50.   long base;
  51.   /* Integral holding variables.  */
  52.   long num;
  53.   unsigned long unum;
  54.  
  55.   /* Workspace.  */
  56.   char work[200];
  57.   char *w;        /* Pointer into WORK.  */
  58.   long param_num = 1; /* start on (0 and 1 is the first strings) 2nd param! */
  59.  
  60.   if (format == NULL) {
  61.     input_error();
  62.   }
  63.  
  64.   c = inchar();
  65.  
  66.   /* Run through the format string.  */
  67.   while (*f != '\0') {
  68.     fc = *f++;
  69.     if (fc != '%') {
  70.       /* Characters other than format specs must just match.  */
  71.       if (c == EOF)
  72.       input_error();
  73.       if (isspace(fc)) {
  74.     /* Whitespace characters match any amount of whitespace.  */
  75.     while (isspace (c))
  76.         inchar ();
  77.     continue;
  78.       }
  79.       else if (c == fc)
  80.       (void) inchar();
  81.       else
  82.       conv_error();
  83.       continue;
  84.     }
  85.  
  86.     /* Check for the assignment-suppressant.  */
  87.     if (*f == '*') {
  88.       do_assign = 0;
  89.       ++f;
  90.     }
  91.     else
  92.     do_assign = 1;
  93.         
  94.     /* Find the maximum field width.  */
  95.     width = 0;
  96.     while (isdigit(*f)) {
  97.       width *= 10;
  98.       width += *f++ - '0';
  99.     }
  100.     if (width == 0)
  101.     width = -1;
  102.  
  103.     /* Check for type modifiers.  */
  104.     is_short = is_long = is_long_double = 0;
  105.     while (*f == 'h' || *f == 'l' || *f == 'L')
  106.     switch (*f++) {
  107.     case 'h':
  108. #if 0
  109.       /* int's are short int's.  */
  110.       is_short = 1;
  111.       break;
  112. #endif
  113.     case 'l':
  114. #if 0
  115.       if (is_long)
  116.           /* A double `l' is equivalent to an `L'.  */
  117.           is_longlong = 1;
  118.       else
  119.           /* int's are long int's.  */
  120.           is_long = 1;
  121.       break;
  122. #endif
  123.     case 'L':
  124. #if 0
  125.       /* double's are long double's, and int's are long long int's.  */
  126.       is_long_double = 1;
  127. #endif
  128.       break;
  129.     }
  130.  
  131.     /* End of the format string?  */
  132.     if (*f == '\0')
  133.     conv_error();
  134.  
  135.     /* Find the conversion specifier.  */
  136.     w = work;
  137.     fc = *f++;
  138.     if (fc != '[' && fc != 'c' && fc != 'n')
  139.     /* Eat whitespace.  */
  140.     while (isspace(c))
  141.         (void) inchar();
  142.     switch (fc) {
  143.     case '%':    /* Must match a literal '%'.  */
  144.       if (c != fc)
  145.       conv_error();
  146.       break;
  147.  
  148.     case 'n':    /* Answer number of assignments done.  */
  149.       if (do_assign) {
  150.     if(++param_num>=argc)
  151.         return -1;
  152.     if(param_types[param_num] == FPL_INTVARARG) {
  153.       ident = (struct Identifier *) param_array[param_num];
  154.       ident->data.variable.var.val32[0] = read_in;
  155.     }
  156.     else
  157.         conv_error();
  158.       }
  159.       break;
  160.  
  161.     case 'c':    /* Match characters.  */
  162.       if (do_assign) {
  163.     if(++param_num>=argc)
  164.         return -1;
  165.     if(param_types[param_num] == FPL_STRVARARG) {
  166.       ident = (struct Identifier *) param_array[param_num];
  167.       if(ident->data.variable.var.str[0])
  168.           FREE_KIND(ident->data.variable.var.str[0]);
  169.       ident->data.variable.var.str[0]=NULL;
  170.     }
  171.     else
  172.         conv_error();
  173.       }
  174.       if (c == EOF)
  175.       input_error();
  176.       if (width == -1)
  177.       width = 1;
  178.       if (do_assign) {
  179.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
  180.                ADD_RESET));
  181.     do {
  182.       SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
  183.     } while (inchar() != EOF && --width > 0);
  184.       }
  185.       else
  186.       while (inchar() != EOF && width > 0)
  187.           --width;
  188.       
  189.       if (do_assign) {
  190.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
  191.     ++done;
  192.       }
  193.  
  194.       if (c == EOF)
  195.       input_error();
  196.       break;
  197.       
  198.     case 's':    /* Read a string.  */
  199.       if (do_assign) {
  200.     if(++param_num>=argc)
  201.         return -1;
  202.     if(param_types[param_num] == FPL_STRVARARG) {
  203.       ident = (struct Identifier *) param_array[param_num];
  204.       if(ident->data.variable.var.str[0])
  205.           FREE_KIND(ident->data.variable.var.str[0]);
  206.       ident->data.variable.var.str[0]=NULL;
  207.     }
  208.     else
  209.         conv_error();
  210.       }
  211.       if (c == EOF)
  212.       input_error();
  213.  
  214.       if(do_assign) {
  215.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
  216.                ADD_RESET));
  217.       }
  218.       do {
  219.     if (isspace(c))
  220.         break;
  221.     if (do_assign) {
  222.       SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
  223.     }
  224.       } while (inchar() != EOF && (width <= 0 || --width > 0));
  225.  
  226.       if (do_assign) {
  227.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
  228.     ++done;
  229.       }
  230.       break;
  231.  
  232.     case 'x':    /* Hexadecimal integer.  */
  233.     case 'X':    /* Ditto.  */ 
  234.       base = 16;
  235.       goto number;
  236.  
  237.     case 'o':    /* Octal integer.  */
  238.       base = 8;
  239.       goto number;
  240.  
  241.     case 'u':    /* Decimal integer.  */
  242.     case 'd':    /* Ditto.  */
  243.       base = 10;
  244.       goto number;
  245.  
  246.     case 'i':    /* Generic number.  */
  247.       base = 0;
  248.  
  249.     number:;
  250.       if (c == EOF)
  251.       input_error();
  252.  
  253.       /* Check for a sign.  */
  254.       if (c == '-' || c == '+') {
  255.     *w++ = c;
  256.     if (width > 0)
  257.         --width;
  258.     (void) inchar();
  259.       }
  260.  
  261.       /* Look for a leading indication of base.  */
  262.       if (c == '0') {
  263.     if (width > 0)
  264.         --width;
  265.     *w++ = '0';
  266.     (void) inchar();
  267.     if (tolower(c) == 'x') {
  268.       if (base == 0)
  269.           base = 16;
  270.       if (base == 16) {
  271.         if (width > 0)
  272.         --width;
  273.         (void) inchar();
  274.       }
  275.     }
  276.     else if (base == 0)
  277.         base = 8;
  278.       }
  279.       if (base == 0)
  280.       base = 10;
  281.  
  282.       /* Read the number into WORK.  */
  283.       do {
  284.     if (base == 16 ? !isxdigit(c) :
  285.         (!isdigit(c) || c - '0' >= base))
  286.         break;
  287.     *w++ = c;
  288.     if (width > 0)
  289.         --width;
  290.       } while (inchar() != EOF && width != 0);
  291.  
  292.       if (w == work ||
  293.       (w - work == 1 && (work[0] == '+' || work[0] == '-')))
  294.       /* There was on number.  */
  295.       conv_error();
  296.  
  297.       /* Convert the number.  */
  298.       *w = '\0';
  299.       num = Strtol(work, base, &w);
  300.       if (w == work)
  301.       conv_error();
  302.  
  303.       if (do_assign) {
  304.     if(++param_num>=argc)
  305.         return -1;
  306.     if(param_types[param_num] == FPL_INTVARARG) {
  307.       ident = (struct Identifier *) param_array[param_num];
  308.       ident->data.variable.var.val32[0] = num;
  309.     }
  310.     else
  311.         conv_error();
  312.     ++done;
  313.       }
  314.       break;
  315.  
  316.     case '[':    /* Character class.  */
  317.       if (do_assign) {
  318.     if(++param_num>=argc)
  319.         return -1;
  320.     if(param_types[param_num] == FPL_STRVARARG) {
  321.       ident = (struct Identifier *) param_array[param_num];
  322.       if(ident->data.variable.var.str[0])
  323.           FREE_KIND(ident->data.variable.var.str[0]);
  324.       ident->data.variable.var.str[0]=NULL;
  325.     }
  326.     else
  327.         conv_error();
  328.       }
  329.       if (c == EOF)
  330.       input_error();
  331.       if (*f == '^') {
  332.     ++f;
  333.     not_in = 1;
  334.       }
  335.       else
  336.       not_in = 0;
  337.       while ((fc = *f++) != '\0' && fc != ']') {
  338.     if (fc == '-' && *f != '\0' && *f != ']' &&
  339.         w > work && w[-1] <= *f)
  340.         /* Add all characters from the one before the '-'
  341.            up to (but not including) the next format char.  */
  342.         for (fc = w[-1] + 1; fc < *f; ++fc)
  343.         *w++ = fc;
  344.     else
  345.         /* Add the character to the list.  */
  346.         *w++ = fc;
  347.       }
  348.       if (fc == '\0')
  349.       conv_error();
  350.       *w = '\0';
  351.       unum = read_in;
  352.       if(do_assign) {
  353.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0],
  354.                ADD_RESET));
  355.       }
  356.  
  357.       do {
  358.     if ((strchr(work, c) == NULL) != not_in)
  359.         break;
  360.     if (do_assign) {
  361.       SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], c));
  362.     }
  363.     if (width > 0)
  364.         --width;
  365.       } while (inchar() != EOF && width != 0);
  366.  
  367.       if (read_in == unum)
  368.       conv_error();
  369.  
  370.       if (do_assign) {
  371.     SCALL(AddCharBuffer(scr, &ident->data.variable.var.str[0], ADD_FLUSH));
  372.     ++done;
  373.       }
  374.       break;
  375.  
  376.     case 'p':    /* Generic pointer.  */
  377.       base = 16;
  378.       /* A PTR must be the same size as a `long int'.  */
  379.       is_long = 1;
  380.       goto number;
  381.     }
  382.   }
  383.   conv_error();
  384. }
  385.